package marco.android.CouchControl;

import marco.android.CouchControl.TouchPadPanel.TouchPadPanelListener;
import marco.android.CouchControl.TouchPadPanel.TouchPadToSurfaceListener;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.opengl.GLSurfaceView;
import android.os.Vibrator;
import android.util.AttributeSet;
import android.view.MotionEvent;

public class GLSurface extends GLSurfaceView implements TouchPadToSurfaceListener
{
	private GLRendererThread mRenderer;
	private TouchPadPanel mPanel;
	private float mDt = 1.f / 60.f;
	private GLTimingLoop mTimingLoop = null;
	private AccelerationListener mAccelerationListener = null;
	private Sensor mAccelerometer = null;
	private SensorManager mSensManager;
	
	public GLSurface(Context context, AttributeSet attrs)
	{
		super(context, attrs);
		mRenderer = new GLRendererThread(context, mDt);
		setRenderer(mRenderer);
		setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
		mPanel = new TouchPadPanel(context, attrs);
		mPanel.SetDrawingListener(this);
		
		mAccelerationListener = new AccelerationListener();
		mSensManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
		mAccelerometer = mSensManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
	}
	
	private class GLTimingLoop extends Thread
	{
		GLTimingLoop()
		{
			super("GLTimingLoop");
		}
		
		@Override
		public void run()
		{
			while(!isInterrupted())
			{
				requestRender();
				try
				{
					Thread.sleep((long)(mDt * 1000));
				}
				catch(InterruptedException e)
				{
					e.printStackTrace();
					break;
				}
			}
		}
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event)
	{
		mPanel.onTouchEvent(event);
		return(true);
	}
	
	public void SetEventListener(TouchPadPanelListener listener)
	{
		mPanel.SetListener(listener);
	}
	
	@Override
	public void onPause()
	{
		mSensManager.unregisterListener(mAccelerationListener, mAccelerometer);
		if(mTimingLoop != null)
		{
			mTimingLoop.interrupt();
		}
		//AccelerometerManager.stopListening(mAccelerationListener);
		super.onPause();
	}

	@Override
	public void onResume()
	{
		mSensManager.registerListener(mAccelerationListener, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
		mTimingLoop = null;
		mTimingLoop = new GLTimingLoop();
		mTimingLoop.start();
//		if(AccelerometerManager.isSupported(getContext()))
//		{
//		   AccelerometerManager.startListening(getContext(), mAccelerationListener, mAccelerometer);
//		}
		super.onResume();
	}
	
	@Override
	public void onDown(final float x, final float y)
	{
		queueEvent(new Runnable()
		{
			public void run()
			{
				mRenderer.onDown(x, y);
			}
		});
	}

	@Override
	public boolean isWithinBounds(final float x, final float y, final float z)
	{
		return(x > 0.f && x < getWidth() &&
			   y > 0.f && y < getHeight());
	}

	@Override
	public void onDrag(final float dx, final float dy)
	{
		if(Math.abs(dx) >= 1 || Math.abs(dy) >= 1)
		{
			queueEvent(new Runnable()
			{
				public void run()
				{
				   mRenderer.onDrag(dx, dy);
				}
			});
		}
	}

	@Override
	public void onScale(final float scaleFactor, final float focusX, final float focusY)
	{
		queueEvent(new Runnable()
		{
			public void run()
			{
			   mRenderer.onScale(scaleFactor, focusX, focusY);
			}
		});
	}

	@Override
	public void onUp(final float x, final float y)
	{
		queueEvent(new Runnable()
		{
			public void run()
			{
			   mRenderer.onUp(x, y);
			}
		});
	}

	@Override
	public void onDoubleTap(final float x, final float y)
	{
		// TODO Auto-generated method stub

	}

	@Override
	public void onFling(final float dx, final float dy, final long durationMilliSecs)
	{
		queueEvent(new Runnable()
		{
			public void run()
			{
			   mRenderer.onFling(dx, dy, durationMilliSecs);
			}
		});
	}

	@Override
	public void onLongPress(final float x, final float y)
	{
		// TODO Auto-generated method stub

	}
	
	private class AccelerationListener implements SensorEventListener
	{
		@Override
		public void onAccuracyChanged(Sensor sensor, int accuracy)
		{
			// TODO Auto-generated method stub
			
		}

		@Override
		public void onSensorChanged(SensorEvent event)
		{
			switch(event.sensor.getType())
			{
			case(Sensor.TYPE_ACCELEROMETER):
				// alpha is calculated as t / (t + dT)
				// with t, the low-pass filter's time-constant
				// and dT the event delivery rate

				final float alpha = 0.8f;
				final float [] gravity = new float[3];
				gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];
				gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1];
				gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2];

				final float [] linear_acceleration = new float[3];
				linear_acceleration[0] = event.values[0] - gravity[0];
				linear_acceleration[1] = event.values[1] - gravity[1];
				linear_acceleration[2] = event.values[2] - gravity[2];

				queueEvent(new Runnable()
				{
					public void run()
					{
						mRenderer.onAcelerationChange(gravity, linear_acceleration);
					}
				});
				break;
			}
		}
		
	}
}
